#include "wiiuse.h"
#include "actionset.h"
#include <cstdlib>
#include <fstream>

using namespace std;

extern wiimote** wiimotes;
extern bool WIIMOTE_IR_MOUSE;
extern bool WIIMOTE_ACC_MOUSE;
extern ActionSet actions;
extern CC_ActionSet ccactions;
extern NC_ActionSet ncactions;
extern GTR_ActionSet gtractions;

ActionSet::ActionSet()
{
name = "";
a = "";
b = "";
one = "";
two = "";
plus = "";
minus = "";
up = "";
down = "";
left = "";
right = "";
home = "";
return;
}

ActionSet::ActionSet(string action_data)
{
name = "null profile";
a = "";
b = "";
one = "";
two = "";
plus = "";
minus = "";
up = "";
down = "";
left = "";
right = "";
home = "";

WIIMOTE_ACC_MOUSE = false; // will only get set to true if it is in this profile
WIIMOTE_IR_MOUSE = false; // will only get set to true if it is in this profile

string taglist[] = {"title", "a", "b", "1", "2", "home", "plus", 
                    "minus", "up", "down", "left", "right", "flick",
                    "ir_mouse", "acc_mouse", "led1", "led2", "led3", "led4"};
int numtags = 19;

string someline, value;
bool eof = false;
int led_set = WIIMOTE_LED_NONE;
while (!eof)
    {
    eof = get_string_line(action_data, someline);
    for (int i=0;i < numtags;i++)
        {
        if (someline.find("["+taglist[i]+"]",0) != string::npos &&
            someline.find("[/"+taglist[i]+"]",0) != string::npos)
            {
            /* cout << taglist[i] << " tag found." << endl
                 << "Tag Length: " << taglist[i].length() << endl; */
            string::size_type start = someline.find("["+taglist[i]+"]",0)+taglist[i].length()+2,
                              end   = someline.find("[/"+taglist[i]+"]",0) - start;
            value = someline.substr(start,end);
            /* cout << "Extrated Value: " << value << endl; */
            switch (i)
                {
                case 0: // title tag
                    name = value;
                    cout << "Loaded Config File: " << value << endl; // display config title
                    break;
                case 1: // a tag
                    a = value;
                    break;
                case 2: // b tag
                    b = value;
                    break;
                case 3: // 1 tag
                    one = value;
                    break;
                case 4: // 2 tag
                    two = value;
                    break;
                case 5: // home tag
                    home = value;
                    break;
                case 6: // plus tag
                    plus = value;
                    break;
                case 7: // minus tag
                    minus = value;
                    break;
                case 8: // up tag
                    up = value;
                    break;
                case 9: // down tag
                    down = value;
                    break;
                case 10: // left tag
                    left = value;
                    break;
                case 11: // right tag
                    right = value;
                    break;
                case 12: // flick tag
                    flick = value;
                    break;
                case 13: // ir_mouse tag
                    if (value.find("x",0) != string::npos)
                    {
                        int x_res, y_res;
                        start = 0;
                        end = value.find("x",0);
                        x_res = atoi(value.substr(start,end).c_str());
                        start = end+1;
                        y_res = atoi(value.substr(start).c_str());
                        wiiuse_set_ir(wiimotes[0], 1);
                        wiiuse_set_ir_vres(wiimotes[0], x_res, y_res);
                        WIIMOTE_IR_MOUSE = true;
                        cout << "IR Mouse enabled" << endl;
                    }
                    else
                    {
                        cout << "Bad screen resolution specified in [ir_mouse] tag." << endl;
                    }
                    break;
                case 14: // acc_mouse tag
                    if (atoi(value.c_str()) == 1)
                        {              
                        WIIMOTE_ACC_MOUSE = true;
                        cout << "ACC Mouse enabled" << endl;
                        }
                    break;
                case 15: // led1 tag
                    if (atoi(value.c_str()) == 1)                
                        {
                        led_set |= WIIMOTE_LED_1;
                        }
                    break;
                case 16: // led2 tag
                    if (atoi(value.c_str()) == 1)                
                        {
                        led_set |= WIIMOTE_LED_2;
                        }
                    break;
                case 17: // led3 tag
                    if (atoi(value.c_str()) == 1)                
                        {
                        led_set |= WIIMOTE_LED_3;
                        }
                    break;
                case 18: // led4 tag
                    if (atoi(value.c_str()) == 1)                
                        {
                        led_set |= WIIMOTE_LED_4;
                        }
                    break;
                default:
                    break;
                }
            }
        }
    }
if (!WIIMOTE_IR_MOUSE)
{
wiiuse_set_ir(wiimotes[0], 0);
}
wiiuse_set_leds(wiimotes[0], led_set);
return;
}

CC_ActionSet::CC_ActionSet()
{
a = "";
b = "";
x = "";
y = "";
plus = "";
minus = "";
d_up = "";
d_down = "";
d_left = "";
d_right = "";
home = "";
l_part = "";
r_part = "";
l = "";
r = "";
zl = "";
zr = "";
ls_up = "";
ls_down = "";
ls_left = "";
ls_right = "";
rs_up = "";
rs_down = "";
rs_left = "";
rs_right = "";
return;
}

CC_ActionSet::CC_ActionSet(string action_data)
{
a = "";
b = "";
x = "";
y = "";
plus = "";
minus = "";
d_up = "";
d_down = "";
d_left = "";
d_right = "";
home = "";
l_part = "";
r_part = "";
l = "";
r = "";
zl = "";
zr = "";
ls_up = "";
ls_down = "";
ls_left = "";
ls_right = "";
rs_up = "";
rs_down = "";
rs_left = "";
rs_right = "";
string taglist[] = {"cc_a", "cc_b", "cc_x", "cc_y", "cc_home", "cc_plus", "cc_minus", 
                    "cc_dpad_up", "cc_dpad_down", "cc_dpad_left", "cc_dpad_right",
                    "cc_zl", "cc_zr", "cc_l", "cc_r",
                    "cc_ls_up", "cc_ls_down", "cc_ls_left", "cc_ls_right",
                    "cc_rs_up", "cc_rs_down", "cc_rs_left", "cc_rs_right",
                    "cc_l_part", "cc_r_part" };
int numtags = 25;

string someline, value;
bool eof = false;
while (!eof)
    {
    eof = get_string_line(action_data, someline);
    for (int i=0;i < numtags;i++)
        {
        if (someline.find("["+taglist[i]+"]",0) != string::npos &&
            someline.find("[/"+taglist[i]+"]",0) != string::npos)
            {
            /*cout << taglist[i] << " tag found." << endl
                 << "Tag Length: " << taglist[i].length() << endl; */
            string::size_type start = someline.find("["+taglist[i]+"]",0)+taglist[i].length()+2,
                              end   = someline.find("[/"+taglist[i]+"]",0) - start;
            value = someline.substr(start,end);
            /* cout << "Extrated Value: " << value << endl; */
            switch (i)
                {
                case 0: // cc_a tag
                    a = value;
                    break;
                case 1: // cc_b tag
                    b = value;
                    break;
                case 2: // cc_x tag
                    x = value;
                    break;
                case 3: // cc_y tag
                    y = value;
                    break;
                case 4: // cc_home tag
                    home = value;
                    break;
                case 5: // cc_plus tag
                    plus = value;
                    break;
                case 6: // cc_minus tag
                    minus = value;
                    break;
                case 7: // cc_dpad_up tag
                    d_up = value;
                    break;
                case 8: // cc_dpad_down tag
                    d_down = value;
                    break;
                case 9: // cc_dpad_left tag
                    d_left = value;
                    break;
                case 10: // cc_dpad_right tag
                    d_right = value;
                    break;
                case 11: // cc_zl tag
                    zl = value;
                    break;
                case 12: // cc_zr tag
                    zr = value;
                    break;
                case 13: // cc_l tag
                    l = value;
                    break;
                case 14: // cc_r tag
                    r = value;
                    break;
                case 15: // cc_ls_up tag
                    ls_up = value;
                    break;
                case 16: // cc_ls_down tag
                    ls_down = value;
                    break;
                case 17: // cc_ls_left tag
                    ls_left = value;
                    break;
                case 18: // cc_ls_right tag
                    ls_right = value;
                    break;
                case 19: // cc_rs_up tag
                    rs_up = value;
                    break;
                case 20: // cc_rs_down tag
                    rs_down = value;
                    break;
                case 21: // cc_rs_left tag
                    rs_left = value;
                    break;
                case 22: // cc_rs_right tag
                    rs_right = value;
                    break;
                case 23: // cc_l_part tag
                    l_part = value;
                    break;
                case 24: // cc_r_part tag
                    r_part = value;
                    break;
                default:
                    break;
                }
            }
        }
    }
return;
}

NC_ActionSet::NC_ActionSet()
{
c = "";
z = "";
stick_up = "";
stick_down = "";
stick_left = "";
stick_right = "";
flick = "";
return;
}

NC_ActionSet::NC_ActionSet(string action_data)
{
c = "";
z = "";
stick_up = "";
stick_down = "";
stick_left = "";
stick_right = "";
flick = "";

string taglist[] = {"nc_c", "nc_z",
                    "nc_stick_up", "nc_stick_down", "nc_stick_left", "nc_stick_right", 
                    "nc_flick" };
int numtags = 7;

string someline, value;
bool eof = false;
while (!eof)
    {
    eof = get_string_line(action_data, someline);
    for (int i=0;i < numtags;i++)
        {
        if (someline.find("["+taglist[i]+"]",0) != string::npos &&
            someline.find("[/"+taglist[i]+"]",0) != string::npos)
            {
            string::size_type start = someline.find("["+taglist[i]+"]",0)+taglist[i].length()+2,
                              end   = someline.find("[/"+taglist[i]+"]",0) - start;
            value = someline.substr(start,end);
            switch (i)
                {
                case 0: // nc_c tag
                    c = value;
                    break;
                case 1: // nc_z tag
                    z = value;
                    break;
                case 2: // nc_stick_up tag
                    stick_up = value;
                    break;
                case 3: // nc_stick_down tag
                    stick_down = value;
                    break;
                case 4: // nc_stick_left tag
                    stick_left = value;
                    break;
                case 5: // nc_stick_right tag
                    stick_right = value;
                    break;
                case 6: // nc_flick tag
                    flick = value;
                    break;
                default:
                    break;
                }
            }
        }
    }
return;
}

GTR_ActionSet::GTR_ActionSet()
{
green = "";
red = "";
yellow = "";
blue = "";
orange = "";
strum_up = "";
strum_down = "";
js_up = "";
js_down = "";
js_left = "";
js_right = "";
plus = "";
minus = "";
whammy = "";
return;
}

GTR_ActionSet::GTR_ActionSet(string action_data)
{
green = "";
red = "";
yellow = "";
blue = "";
orange = "";
strum_up = "";
strum_down = "";
js_up = "";
js_down = "";
js_left = "";
js_right = "";
plus = "";
minus = "";
whammy = "";

string taglist[] = {"green", "red", "yellow", "blue", "orange", "strum_up", "strum_down",
                    "gtr_stick_up", "gtr_stick_down", "gtr_stick_left", "gtr_stick_right", 
                    "gtr_minus", "gtr_plus", "whammy" };
int numtags = 14;

string someline, value;
bool eof = false;
while (!eof)
    {
    eof = get_string_line(action_data, someline);
    for (int i=0;i < numtags;i++)
        {
        if (someline.find("["+taglist[i]+"]",0) != string::npos &&
            someline.find("[/"+taglist[i]+"]",0) != string::npos)
            {
            string::size_type start = someline.find("["+taglist[i]+"]",0)+taglist[i].length()+2,
                              end   = someline.find("[/"+taglist[i]+"]",0) - start;
            value = someline.substr(start,end);
            switch (i)
                {
                case 0: // green
                    green = value;
                    break;
                case 1: // red
                    red = value;
                    break;
                case 2: // yellow
                    yellow = value;
                    break;
                case 3: // blue
                    blue = value;
                    break;
                case 4: // orange
                    orange = value;
                    break;
                case 5: // strum_up
                    strum_up = value;
                    break;
                case 6: // strum_down
                    strum_down = value;
                    break;
                case 7: // gtr_stick_up
                    js_up = value;
                    break;
                case 8: // gtr_stick_down
                    js_down = value;
                    break;
                case 9: // gtr_stick_left
                    js_left = value;
                    break;
                case 10: // gtr_stick_right
                    js_right = value;
                    break;
                case 11: // gtr_minus
                    minus = value;
                    break;
                case 12: // gtr_plus
                    plus = value;
                    break;
                case 13: // whammy
                    whammy = value;
                    break;
                default:
                    break;
                }
            }
        }
    }
return;
}

bool get_string_line(string &src, string &line)
{
size_t endpos = src.find('\n');
if (endpos == string::npos)
    {
    line = src.substr(0, (src.length()-1));
    src = "";
    return true; // eof reached
    }
else
    {
    line = src.substr(0, endpos);
    src = src.substr((endpos+1), (src.length()-1));
    return false; // eof still to come
    }
}

void execute_action(string event, stateType type)
{
string::size_type loc = event.find(" ");
string command = event.substr(0, loc);
if (command == "KEYBOARD")
    {
    //
    //  My thanks to Rémy Sanchez for altering this piece of code to 
    //  allow mapping Wiimote buttons to key combinations instead of only
    //  single keys.
    //
    int event_length = event.length();
    bool release;
    
    if(type == RELEASED) {
    	release = true;
    }
    else {
    	release = false;
    }
    
    for(int i=(loc+1); i<event_length; i++) {
    	string::size_type pos = event.find(" ", i);
    	if(pos == string::npos) pos = event_length;
    	
    	XIUseKeyboard(get_x_keycode_from_string(event.substr(i,pos-i)), release);
    	
    	i += pos-i;
    }
    
    }
else if (command == "MOUSECLICK")
    {
    string keystr = event.substr(loc+1);
    int btncode = atoi(keystr.c_str());
        switch (type)
            {
            case RELEASED:
                XIClickMouse(btncode, true);
                break;
            case PRESSED:
                XIClickMouse(btncode, false);
                break;
            default:
                break;
            }
    }
else if (command == "MENUPROFILE")
    {
    system("python prova.py > resultat");
    ifstream profile;
    profile.open("resultat", ios::in);
    
    if (!profile.is_open())
    {
        cout << "Could not open specified config file for reading.  Exiting..." << endl;
        exit(1);
    }
    string profile_data = "";
    string line;
    while (!profile.eof())
        {
        getline(profile, line);
        profile_data += line + "\n";
        }
    cout << profile_data << endl;
    profile.close();

    actions = ActionSet(profile_data);
    ccactions = CC_ActionSet(profile_data);
    ncactions = NC_ActionSet(profile_data);
    gtractions = GTR_ActionSet(profile_data);
    system("rm resultat");
    }
else if (command == "SWITCHPROFILE" && type == PRESSED)
    {
    string keystr = event.substr(loc+1);
    ifstream profile;
    profile.open(keystr.c_str(), ios::in);
    if (!profile.is_open())
    {
    cout << "Could not open specified config file for reading.  Exiting..." << endl;
    exit(1);
    }
    char c;
    string profile_data = "";
    while (!profile.eof()) { profile.get(c); profile_data += c; }
    profile.close();
    
    actions = ActionSet(profile_data);
    ccactions = CC_ActionSet(profile_data);
    ncactions = NC_ActionSet(profile_data);
    gtractions = GTR_ActionSet(profile_data);
    }
else if (type == PRESSED) // just execute the string as a command
    {
    event += " > /dev/null";  // who cares about the output.  Change this if you do.
    system(event.c_str());
    }
return;
}

string ActionSet::get_name()
{
return name;
}

InputState::InputState()
{
a = false;
b = false;
one = false;
two = false;
plus = false;
minus = false;
up = false;
down = false;
left = false;
right = false;
home = false;
flick = false;
a_type = NO_CHANGE;
b_type = NO_CHANGE;
one_type = NO_CHANGE;
two_type = NO_CHANGE;
plus_type = NO_CHANGE;
minus_type = NO_CHANGE;
up_type = NO_CHANGE;
down_type = NO_CHANGE;
left_type = NO_CHANGE;
right_type = NO_CHANGE;
home_type = NO_CHANGE;
flick_type = NO_CHANGE;
}

CC_InputState::CC_InputState(bool releaseAll)
{
a = releaseAll;
b = releaseAll;
x = releaseAll;
y = releaseAll;
plus = releaseAll;
minus = releaseAll;
home = releaseAll;
d_up = releaseAll;
d_down = releaseAll;
d_left = releaseAll;
d_right = releaseAll;
l_part = releaseAll;
r_part = releaseAll;
l = releaseAll;
r = releaseAll;
zl = releaseAll;
zr = releaseAll;
ls_up = releaseAll;
ls_down = releaseAll;
ls_left = releaseAll;
ls_right = releaseAll;
rs_up = releaseAll;
rs_down = releaseAll;
rs_left = releaseAll;
rs_right = releaseAll;

stateType base_type;
if (releaseAll) { base_type = RELEASED; }
else { base_type = NO_CHANGE; }

a_type = base_type;
b_type = base_type;
x_type = base_type;
y_type = base_type;
plus_type = base_type;
minus_type = base_type;
home_type = base_type;
d_up_type = base_type;
d_down_type = base_type;
d_left_type = base_type;
d_right_type = base_type;
l_part_type = base_type;
r_part_type = base_type;
l_type = base_type;
r_type = base_type;
zl_type = base_type;
zr_type = base_type;
ls_up_type = base_type;
ls_down_type = base_type;
ls_left_type = base_type;
ls_right_type = base_type;
rs_up_type = base_type;
rs_down_type = base_type;
rs_left_type = base_type;
rs_right_type = base_type;
}

NC_InputState::NC_InputState(bool releaseAll)
{
c = releaseAll;
z = releaseAll;
stick_up = releaseAll;
stick_down = releaseAll;
stick_left = releaseAll;
stick_right = releaseAll;
flick = releaseAll;

stateType base_type;
if (releaseAll) { base_type = RELEASED; }
else { base_type = NO_CHANGE; }

c_type = base_type;
z_type = base_type;
stick_up_type = base_type;
stick_down_type = base_type;
stick_left_type = base_type;
stick_right_type = base_type;
flick_type = base_type;
}

GTR_InputState::GTR_InputState(bool releaseAll)
{
green = releaseAll;
red = releaseAll;
yellow = releaseAll;
blue = releaseAll;
orange = releaseAll;
strum_up = releaseAll;
strum_down = releaseAll;
plus = releaseAll;
minus = releaseAll;
js_up = releaseAll;
js_down = releaseAll;
js_left = releaseAll;
js_right = releaseAll;
whammy = releaseAll;

stateType base_type;
if (releaseAll) { base_type = RELEASED; }
else { base_type = NO_CHANGE; }

green_type = base_type;
red_type = base_type;
yellow_type = base_type;
blue_type = base_type;
orange_type = base_type;
strum_up_type = base_type;
strum_down_type = base_type;
plus_type = base_type;
minus_type = base_type;
js_up_type = base_type;
js_down_type = base_type;
js_left_type = base_type;
js_right_type = base_type;
whammy_type = base_type;
}

void xwii_process_input(InputState &istate, ActionSet &actions)
{
if (istate.a)
    {
    execute_action(actions.a, istate.a_type);
    }
if (istate.b)
    {
    execute_action(actions.b, istate.b_type);
    }
if (istate.one)
    {
    execute_action(actions.one, istate.one_type);
    }
if (istate.two)
    {
    execute_action(actions.two, istate.two_type);
    }
if (istate.plus)
    {
    execute_action(actions.plus, istate.plus_type);
    }
if (istate.minus)
    {
    execute_action(actions.minus, istate.minus_type);
    }
if (istate.up)
    {
    execute_action(actions.up, istate.up_type);
    }
if (istate.down)
    {
    execute_action(actions.down, istate.down_type);
    }
if (istate.left)
    {
    execute_action(actions.left, istate.left_type);
    }
if (istate.right)
    {
    execute_action(actions.right, istate.right_type);
    }
if (istate.home)
    {
    execute_action(actions.home, istate.home_type);
    }
if (istate.flick)
    {
    execute_action(actions.flick, istate.flick_type);
    }
return;
}

void xwii_process_CC_input(CC_InputState &istate, CC_ActionSet &actions)
{
if (istate.a)
    {
    execute_action(actions.a, istate.a_type);
    }
if (istate.b)
    {
    execute_action(actions.b, istate.b_type);
    }
if (istate.x)
    {
    execute_action(actions.x, istate.x_type);
    }
if (istate.y)
    {
    execute_action(actions.y, istate.y_type);
    }
if (istate.plus)
    {
    execute_action(actions.plus, istate.plus_type);
    }
if (istate.minus)
    {
    execute_action(actions.minus, istate.minus_type);
    }
if (istate.d_up)
    {
    execute_action(actions.d_up, istate.d_up_type);
    }
if (istate.d_down)
    {
    execute_action(actions.d_down, istate.d_down_type);
    }
if (istate.d_left)
    {
    execute_action(actions.d_left, istate.d_left_type);
    }
if (istate.d_right)
    {
    execute_action(actions.d_right, istate.d_right_type);
    }
if (istate.home)
    {
    execute_action(actions.home, istate.home_type);
    }
if (istate.l)
    {
    execute_action(actions.l, istate.l_type);
    }
if (istate.r)
    {
    execute_action(actions.r, istate.r_type);
    }
if (istate.l_part)
    {
    execute_action(actions.l_part, istate.l_part_type);
    }
if (istate.r_part)
    {
    execute_action(actions.r_part, istate.r_part_type);
    }
if (istate.zr)
    {
    execute_action(actions.zr, istate.zr_type);
    }
if (istate.zl)
    {
    execute_action(actions.zl, istate.zl_type);
    }
if (istate.ls_up)
    {
    execute_action(actions.ls_up, istate.ls_up_type);
    }
if (istate.ls_down)
    {
    execute_action(actions.ls_down, istate.ls_down_type);
    }
if (istate.ls_left)
    {
    execute_action(actions.ls_left, istate.ls_left_type);
    }
if (istate.ls_right)
    {
    execute_action(actions.ls_right, istate.ls_right_type);
    }
if (istate.rs_up)
    {
    execute_action(actions.rs_up, istate.rs_up_type);
    }
if (istate.rs_down)
    {
    execute_action(actions.rs_down, istate.rs_down_type);
    }
if (istate.rs_left)
    {
    execute_action(actions.rs_left, istate.rs_left_type);
    }
if (istate.rs_right)
    {
    execute_action(actions.rs_right, istate.rs_right_type);
    }
}

void xwii_process_NC_input(NC_InputState &istate, NC_ActionSet &actions)
{
if (istate.c)
    {
    execute_action(actions.c, istate.c_type);
    }
if (istate.z)
    {
    execute_action(actions.z, istate.z_type);
    }
if (istate.stick_up)
    {
    execute_action(actions.stick_up, istate.stick_up_type);
    }
if (istate.stick_down)
    {
    execute_action(actions.stick_down, istate.stick_down_type);
    }
if (istate.stick_left)
    {
    execute_action(actions.stick_left, istate.stick_left_type);
    }
if (istate.stick_right)
    {
    execute_action(actions.stick_right, istate.stick_right_type);
    }
if (istate.flick)
    {
    cout << "nc flick event" << endl;
    execute_action(actions.flick, istate.flick_type);
    }
}

void xwii_process_GTR_input(GTR_InputState &istate, GTR_ActionSet &actions)
{
if (istate.green)
    {
    execute_action(actions.green, istate.green_type);
    }
if (istate.red)
    {
    execute_action(actions.red, istate.red_type);
    }
if (istate.yellow)
    {
    execute_action(actions.yellow, istate.yellow_type);
    }
if (istate.blue)
    {
    execute_action(actions.blue, istate.blue_type);
    }
if (istate.orange)
    {
    execute_action(actions.orange, istate.orange_type);
    }
if (istate.strum_up)
    {
    execute_action(actions.strum_up, istate.strum_up_type);
    }
if (istate.strum_down)
    {
    execute_action(actions.strum_down, istate.strum_down_type);
    }
if (istate.js_up)
    {
    execute_action(actions.js_up, istate.js_up_type);
    }
if (istate.js_down)
    {
    execute_action(actions.js_down, istate.js_down_type);
    }
if (istate.js_left)
    {
    execute_action(actions.js_left, istate.js_left_type);
    }
if (istate.js_right)
    {
    execute_action(actions.js_right, istate.js_right_type);
    }
if (istate.plus)
    {
    execute_action(actions.plus, istate.plus_type);
    }
if (istate.minus)
    {
    execute_action(actions.minus, istate.minus_type);
    }
if (istate.whammy)
    {
    execute_action(actions.whammy, istate.whammy_type);
    }
}
